﻿/*
 * @Autor: PK
 * @Date: 2022/01/14 20:31:SS
 */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using O2DESNet;
using ShkSimulation.carsharing;
using ShkSimulation.core.dao.input.loader;
using ShkSimulation.core.dao.input.resource;
using ShkSimulation.core.dao.statistic;
using ShkSimulation.core.factory;
using ShkSimulation.core.template;
using ShkSimulation.core.template.agency;
using ShkSimulation.core.template.customer;
using ShkSimulation.core.template.model;

namespace ShkSimulation.carsharing.demo {

	public class QuickBuildNetwork: AbstractNetwork, DataReporter {
        
        private static int uniqueIndex = 1;
        public static int stationCount = 5;
        public static int roadCount = 20;
        public static int initVehicleCount = 10;
        public static double stationServiceRate = 2;
        public static double roadServiceRate = 2;
        public static double DayArriveCount = 1200;

        private HourCounter StationVehicleCounter;
        private HourCounter RoadVehicleCounter;
        private Dictionary<string, ReadOnlyHourCounter> NamedHourCounters = new Dictionary<string, ReadOnlyHourCounter>();

        private QuickBuildNetwork(int id,
            NetworkInputData inputData, 
            NetworkResultCollector resultCollector, 
            DemandManager demandManager, 
            CreateFactoriesFunc factoriesFunc, 
            int seed) : base(id, inputData, resultCollector, demandManager, factoriesFunc, seed) {
            
            DemoDemandManager.DayArriveCount = DayArriveCount;
            
            StationVehicleCounter = AddHourCounter();
            RoadVehicleCounter = AddHourCounter();
            NamedHourCounters.Add("车站车辆数", StationVehicleCounter.AsReadOnly());
            NamedHourCounters.Add("道路车辆数", RoadVehicleCounter.AsReadOnly());
            this.OnSimulationRunning += Running;
            
        }

        private void Running(NetworkRunInfo obj) {
            double stationVehicle = 0;
            double roadVehicle = 0;
            NetworkInputData inputData = this.NetworkInput;
            foreach (var abstractStation in inputData.ClassifiedAgencies[CarsharingConfig.StationResourceKey]) {
                stationVehicle += ((DemoStation)abstractStation).VehicleCount;
            }
            foreach (var abstractRoad in inputData.ClassifiedAgencies[CarsharingConfig.RoadResourceKey]) {
                roadVehicle += ((DemoRoad)abstractRoad).VehicleCount;
            }
            Debug.Assert(Math.Abs(roadVehicle + stationVehicle - initVehicleCount * stationCount) < 0.1);
            StationVehicleCounter.ObserveCount(stationVehicle, ClockTime);
            RoadVehicleCounter.ObserveCount(roadVehicle, ClockTime);
        }

        public static QuickBuildNetwork BuildNetwork() {
            NetworkEnvironment inputData = new NetworkEnvironment(InputConfig.Empty(), new EmptyResourceLoader());
            return new QuickBuildNetwork(-1, inputData, new NetworkResultHolder(), new DemoDemandManager(), FactoriesCreateFunction, 1);
        }
        
                
        protected static List<AgencyFactory> FactoriesCreateFunction(NetworkInputData networkInput) {
            AgencyFactory station = DefaultStationFactory(networkInput);
            AgencyFactory road = DefaultRoadFactory(networkInput);
            return new List<AgencyFactory>() {
                station, road
            };
        }
        
        protected static AgencyFactory DefaultStationFactory(NetworkInputData networkInput) {
            return FactoryProvider.CreateFactory("station", CreateDemoStations);
            Dictionary<int, Agency> CreateDemoStations(Resource resource, List<CreateParam> createParams) {
                Dictionary<int, Agency> result = new Dictionary<int, Agency>();
                for (int i = 0; i < stationCount; i++) {
                    BaseAgencyParams agencyParams = BaseAgencyParams.Create(uniqueIndex++);
                    DemoStation station = new DemoStation(agencyParams, QuickBuildNetwork.initVehicleCount);
                    station.ServiceRateHelper = new StableServiceRateHelper(TimeSpan.FromHours(1 / stationServiceRate));
                    result.Add(agencyParams.UniqueId, station);
                }
                return result;
            }
        }

        protected static AgencyFactory DefaultRoadFactory(NetworkInputData networkInput) {
            return FactoryProvider.CreateFactory("road", CreateDemoRoads);
            Dictionary<int, Agency> CreateDemoRoads(Resource resource, List<CreateParam> createParams) {
                var stations = networkInput.ClassifiedAgencies[CarsharingConfig.StationResourceKey].ToDictionary(each => each.UniqueId, each => each);
                Dictionary<int, Agency> result = new Dictionary<int, Agency>();
                foreach (var (origin, _) in stations) {
                    foreach (var (dest, _) in stations) {
                        if (origin == dest) {
                            continue;
                        }
                        BaseAgencyParams agencyParams = BaseAgencyParams.Create(uniqueIndex++);
                        DemoRoad road = new DemoRoad(agencyParams);
                        road.LastStation = origin;
                        road.NextStation = dest;
                        road.ServiceRateHelper = new StableServiceRateHelper(TimeSpan.FromHours(1 / roadServiceRate));
                        result.Add(agencyParams.UniqueId, road);
                    }
                }
                return result;
            }
        }

        public DataReportInfo GetReportInfo() {
            return DataReportInfo.Create(this.UniqueId.ToString(), ClockTime, NamedHourCounters);
        }
        
        public string Uniquekey => UniqueId.ToString();
    }

}